package com.tron.nettychat.nettysocket;

import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @description TODO
 * @auther TRON
 * @create 2019-12-24
 */
@Slf4j
@Component
public class TronChannelManager implements ApplicationContextAware {

    public static ApplicationContext applicationContext;

    //所有channel保存在这里
    private static ChannelGroup GlobalGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    //channel的长id和短id映射
    private static ConcurrentMap<String, ChannelId> ChannelMap = new ConcurrentHashMap();
    //channel短id和用户id映射
    private static ConcurrentMap<String, String> userMap = new ConcurrentHashMap<>();


    /**
     * 添加连接映射
     *
     * @param channel
     */
    public static void addChannel(Channel channel) {
        GlobalGroup.add(channel);
        ChannelMap.put(channel.id().asShortText(), channel.id());
    }

    /**
     * 添加用户映射
     *
     * @param channelShortId
     * @param userId
     */
    public static void addUser(String channelShortId, String userId) {
        ArrayList<String> ids = new ArrayList<>();
        userMap.forEach((k, v) -> {
            if (v.equals(userId)) {
                ids.add(userId);
            }
        });
        if (ids.size() == 0) {
            userMap.put(channelShortId, userId);
        }
    }


    /**
     * 删除连接映射，用户映射
     *
     * @param channel
     */
    public static void removeChannel(Channel channel) {
        GlobalGroup.remove(channel);
        ChannelMap.remove(channel.id().asShortText());
        userMap.remove(channel.id().asShortText());
    }

    /**
     * 根据Channel短id查找连接
     *
     * @param channelShortId
     * @return
     */
    public static Channel findChannel(String channelShortId) {
        return GlobalGroup.find(ChannelMap.get(channelShortId));
    }

    /**
     * 根据用户ids查找连接列表
     *
     * @param ids
     * @return
     */
    public static List<Channel> findChannelByUserIds(List<String> ids) {
        ArrayList<Channel> channels = new ArrayList<>();
        userMap.forEach((k, v) -> {
            if (ids.contains(v)) {
                channels.add(findChannel(k));
            }
        });
        return channels;
    }


    /**
     * 给所有在线用户发送信息
     *
     * @param msg
     */
    public static void sendAll(String msg) {
        GlobalGroup.writeAndFlush(new TextWebSocketFrame(msg));
    }

    /**
     * 给指定在线用户发送信息
     *
     * @param ids
     * @param msg
     */
    public static void sendFilter(List<String> ids, String msg) {
        //发送消息的业务逻辑
        List<Channel> channels = findChannelByUserIds(ids);
        for (int i = 0; i < channels.size(); i++) {
            channels.get(i).writeAndFlush(new TextWebSocketFrame(msg));
        }
    }

    /**
     * 给指定用户发送消息
     *
     * @param userId
     * @param msg
     * @return 返回0表示用户不在线，返回1表示发送成功
     */
    public static Integer sendMessageByUserId(String userId, String msg) {
        List<Channel> channelByUserIds = findChannelByUserIds(Arrays.asList(userId));
        if (channelByUserIds.size() == 0) {
            return 0;
        }
        channelByUserIds.get(0).writeAndFlush(new TextWebSocketFrame(msg));
        return 1;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (TronChannelManager.applicationContext == null) {
            TronChannelManager.applicationContext = applicationContext;
        }
    }
}
